package com.study.cloud.gateway.common.request;

import com.google.common.collect.Lists;
import com.jayway.jsonpath.JsonPath;

import com.study.cloud.gateway.common.constants.BasicConst;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.asynchttpclient.Request;
import org.asynchttpclient.RequestBuilder;
import org.asynchttpclient.cookie.Cookie;

import java.nio.charset.Charset;
import java.util.*;

/**
 * @author wangwancheng
 * @create 2025/7/17 15:40
 */
@Getter
public class GatewayRequest implements IGatewayRequest{
    /**
     * 请求服务Id
     * 服务:版本
     */
    private final String uniqueId;
    /**
     * 开始时间
     */
    private final Long beginTime;
    /**
     * 字符集
     */
    private final Charset charset;
    /**
     * 客户端ip 主要用于黑白名单的处理
     */
    private final String clientIp;
    /**
     * 请求地址ip:port
     */
    private final String host;
    /**
     * 请求路径
     */
    private final String path;
    /**
     * URL 统一资源定位符
     */
    private final String uri;
    /**
     * 请求方式 post get
     */
    private final HttpMethod method;
    /**
     * 请求格式
     */
    private final String contentType;
    /**
     * 请求头信息
     */
    private final HttpHeaders headers;
    /**
     * 参数解析器
     */
    private final QueryStringDecoder queryStringDecoder;
    /**
     * 该对象可以获取到所有与http协议相关的信息
     */
    private final FullHttpRequest fullHttpRequest;
    /**
     * 请求体
     */
    private String body;
    /**
     * 请求的cookie
     */
    private Map<String, io.netty.handler.codec.http.cookie.Cookie> cookieMap;
    /**
     * post请求定义的参数
     */
    private Map<String, List<String>> postParameters;

    /**
     * 可修改的请求变量
     * scheme默认是http://
     */
    private String modifyScheme;
    private String modifyHost;
    private String modifyPath;
    /**
     * 构建下游http的请求
     */
    private final RequestBuilder requestBuilder;

    public GatewayRequest(String uniqueId, Charset charset, String clientIp, String host,
                          String uri, HttpMethod method, String contentType, HttpHeaders headers,
                          FullHttpRequest fullHttpRequest) {
        this.uniqueId = uniqueId;
        this.beginTime = System.currentTimeMillis();
        this.charset = charset;
        this.clientIp = clientIp;
        this.host = host;

        this.uri = uri;
        this.method = method;
        this.contentType = contentType;
        this.headers = headers;
        this.queryStringDecoder = new QueryStringDecoder( uri,charset);
        this.path = queryStringDecoder.path();
        this.modifyHost = host;
        this.modifyPath = path;
        this.modifyScheme = BasicConst.HTTP_PREFIX_SEPARATOR;
        this.fullHttpRequest = fullHttpRequest;
        ByteBuf byteBuf = fullHttpRequest.content();
        this.requestBuilder = new RequestBuilder();
        this.requestBuilder.setMethod(getMethod().name())
                .setHeaders(getHeaders())
                .setQueryParams(queryStringDecoder.parameters());
        if (Objects.nonNull(byteBuf)){
            this.requestBuilder.setBody(byteBuf.nioBuffer());
        }
    }

    /**
     * 获取请求体
     * @return
     */
    public String getBody() {
        if (StringUtils.isNoneBlank(body)){
            body = fullHttpRequest.content().toString(charset);
        }
        return body;
    }

    /**
     * 获取cookie
     * 将请求中的cookie转换为netty cookie
     * @param name
     * @return
     */
    public io.netty.handler.codec.http.cookie.Cookie getCookie(String name) {
        if (Objects.isNull(cookieMap)){
            cookieMap = new HashMap<String, io.netty.handler.codec.http.cookie.Cookie>();
            String cookieStr = getHeaders().get(HttpHeaderNames.COOKIE);
            if (StringUtils.isNoneBlank(cookieStr)){
                Set<io.netty.handler.codec.http.cookie.Cookie> cookies = ServerCookieDecoder.STRICT.decode(cookieStr);
                for (io.netty.handler.codec.http.cookie.Cookie cookie : cookies) {
                    cookieMap.put(cookie.name(),cookie);
                }
            }
        }
        return cookieMap.get(name);
    }

    /**
     * get 请求获取指定参数名称的参数值
     * @param name
     * @return
     */
    public List<String> getQueryParametersMutiple(String name) {
        return queryStringDecoder.parameters().get(name);
    }

    /**
     * post 请求获取指定参数名称的参数值
     * @param name
     * @return
     */
    public List<String> getPostParametersMutiple(String name) {
        String body = getBody();
        if (isFromPost()){
            if (postParameters == null){
                QueryStringDecoder queryStringDecoder = new QueryStringDecoder(body);
                postParameters = queryStringDecoder.parameters();
            }
            if (postParameters == null || postParameters.isEmpty()){
                return null;
            }else{
                return postParameters.get(name);
            }
        }else if (isJsonPost()){
            return Lists.newArrayList(JsonPath.read(body,name).toString());
        }else {

        }
        return null;
    }

    public boolean isFromPost(){
        return HttpMethod.POST.equals(method) &&
                (contentType.startsWith(HttpHeaderValues.FORM_DATA.toString())
                        || contentType.startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString())
                        );
    }

    public boolean isJsonPost(){
        return HttpMethod.POST.equals(method) &&
                (contentType.startsWith(HttpHeaderValues.APPLICATION_JSON.toString())
                );
    }

    @Override
    public void addHeader(CharSequence name, String value) {
        requestBuilder.addHeader(name,value);
    }

    @Override
    public void setHeader(CharSequence name, String value) {
        requestBuilder.setHeader(name,value);
    }

    @Override
    public void addOrReplaceCookie(Cookie cookie) {
        requestBuilder.addCookie(cookie);
    }

    @Override
    public void setRequestTimeout(int timeout) {
        requestBuilder.setRequestTimeout(timeout);
    }

    @Override
    public void setModifyHost(String modifyHost) {
        this.modifyHost = modifyHost;
    }

    @Override
    public void setModifyPath(String modifyPath) {
        this.modifyPath = modifyPath;
    }

    @Override
    public String getModifyPath() {
        return this.modifyPath;
    }

    @Override
    public void addQueryParam(String name, String value) {
        requestBuilder.addQueryParam(name,value);
    }

    @Override
    public void addFormParam(String name, String value) {
        if (isFromPost()){
            requestBuilder.addFormParam(name,value);
        }
    }

    @Override
    public String getFinalUrl() {
        return modifyScheme+modifyHost+modifyPath;
    }

    @Override
    public Request build() {
        requestBuilder.setUrl(getFinalUrl());
        return requestBuilder.build();
    }
}
